# encoding: utf8

#
# This file is part of JsQt.
#
# Copyright (C) 2009 Arskom Ltd. www.arskom.com.tr
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

import string
from xml import sax

import jsqt

from jsqt.containers import *
from jsqt.widgets import *
from jsqt.layouts import *
from jsqt import Class, Dummy, NoQooxdooEquivalent

try:
    from orderedset import OrderedSet
    JsQtSet=OrderedSet
except: # < python-2.6
    JsQtSet=set
    pass

class_name = ""

#
# This class is where the xml tag and widget handlers are
# registered.
#

class QtUiFileHandler(object):
    members = JsQtSet()
    buffers = []

    tag_entry_handlers = {}
    tag_exit_handlers = {}

    stack = []
    class_handlers = {}
    layout_handlers = {}
    item_attrs = None

    main_container = None

    def __init__(self, js_file_name):
        self.buffer = []
        self.buffers.append(self.buffer)
        self.xmltext_handler = None
        self.js_file = open(js_file_name, 'w')

        self.tag_entry_handlers["property"] = self.property_entry
        self.tag_exit_handlers["property"] = self.property_exit
        self.tag_entry_handlers["attribute"] = self.property_entry
        self.tag_exit_handlers["attribute"] = self.property_exit

        self.tag_entry_handlers["spacer"] = self.spacer_entry
        self.tag_exit_handlers["spacer"] = self.spacer_exit

        self.tag_entry_handlers["widget"] = self.widget_entry
        self.tag_exit_handlers["widget"] = self.widget_exit

        self.tag_entry_handlers["layout"] = self.layout_entry
        self.tag_exit_handlers["layout"] = self.layout_exit

        self.tag_entry_handlers["item"] = self.item_entry
        self.tag_exit_handlers["item"] = self.item_exit

        self.tag_entry_handlers["class"] = self.class_entry
        self.tag_exit_handlers["class"] = self.class_exit

        self.tag_entry_handlers["ui"] = self.ui_entry
        self.tag_exit_handlers["ui"] = self.ui_exit

        # widget definitions
        self.layout_handlers["QVBoxLayout"] = QVBoxLayout
        self.layout_handlers["QHBoxLayout"] = QHBoxLayout
        self.layout_handlers["QGridLayout"] = QGridLayout
        self.layout_handlers["QFormLayout"] = QFormLayout

        self.class_handlers["QScrollArea"] = QScrollArea
        self.class_handlers["QTabWidget"] = QTabWidget
        self.class_handlers["QToolBar"] = QToolBar

        self.class_handlers["QMainWindow"] = QMainWindow
        self.class_handlers["QWidget"] = QWidget
        self.class_handlers["QFrame"] = QWidget

        self.class_handlers["QDateTimeEdit"] = NoQooxdooEquivalent
        self.class_handlers["QTimeEdit"] = NoQooxdooEquivalent

        self.class_handlers["QGraphicsView"] = QWidget

        self.class_handlers["QTableWidget"] = QTableWidget
        self.class_handlers["QListWidget"] = QListWidget

        self.class_handlers["QRadioButton"] = QRadioButton
        self.class_handlers["QPushButton"] = QPushButton
        self.class_handlers["QDateEdit"] = QDateEdit
        self.class_handlers["QLineEdit"] = QLineEdit
        self.class_handlers["QTextEdit"] = QTextEdit
        self.class_handlers["QComboBox"] = QComboBox
        self.class_handlers["QCheckBox"] = QCheckBox
        self.class_handlers["QGroupBox"] = QGroupBox
        self.class_handlers["QSpinBox"] = QSpinBox
        self.class_handlers["QLabel"] = QLabel

        self.class_handlers["Spacer"] = Spacer
        self.class_handlers["Class"] = Class

    def ui_entry(self, attrs):
        self.buffer.append("")
        self.buffer.append("/*")
        self.buffer.append(" * This class is generated by JsQt-%s. If you'd like to make changes to it," % jsqt.version)
        self.buffer.append(" * you should probably extend it.")
        self.buffer.append(" */")
        self.buffer.append("")

    def class_entry(self, attrs):
        self.stack.append(Class(self, class_name, "Class"))

    def property_entry(self, attrs):
        self.stack[-1].set_current_property(attrs.get("name"))

    def widget_entry(self, attrs):
        self.__widget_entry(attrs.get("class"), attrs.get("name"))

    def item_entry(self, attrs):
        self.item_attrs = attrs

    def item_exit(self):
        self.item_attrs = None

    def spacer_entry(self, attrs):
        self.__widget_entry("Spacer", attrs.get("name"))

    def __widget_entry(self, class_name, name):
        if not self.class_handlers.has_key(class_name):
            class_handler = Dummy
        else:
            class_handler = self.class_handlers[class_name]

        tmp = class_handler(self,name,class_name)

        if self.main_container == None:
            self.main_container = tmp

        tmp.item_properties = self.item_attrs
        self.stack.append(tmp)

    def layout_entry(self, attrs):
        layout_name = attrs.get("class")
        if self.layout_handlers.has_key(layout_name):
            layout = self.layout_handlers[layout_name](self, attrs.get("name"))
        else:
            layout = None

        if self.stack[-1].layout != None:
            if layout == None:
                self.stack.append(Dummy(self, attrs.get("name") + "_absorber", layout_name))
                self.stack[-1].implicit = True
                self.stack[-1].item_properties = self.item_attrs
            else:
                self.stack.append(QWidget(self, attrs.get("name") + "_implicit_container"))
                self.stack[-1].implicit = True
                self.stack[-1].item_properties = self.item_attrs

        else:
            self.stack[-1].implicit = False

        self.stack[-1].set_layout(layout)

    def layout_exit(self):
        self.stack[-1].in_layout = False
        self.stack[-1].close()

        if self.stack[-1].implicit:
            if not isinstance(self.stack[-1], Dummy):
                self.stack[-1].layout.close()
                self.stack[-1].parent.add_widget(self.stack[-1])
            self.stack.pop()

    def property_exit(self):
        self.stack[-1].set_current_property(None)

    def widget_exit(self):
        if len(self.stack) == 0:
            return
        elif self.stack[-1].parent != None:
            self.stack[-1].parent.add_widget(self.stack[-1])

        self.stack[-1].close()
        self.stack.pop()

    def spacer_exit(self):
        self.widget_exit()

    def class_exit(self):
        self.stack.pop()

    def ui_exit(self):
        pass

class QtUiFileParser(sax.ContentHandler, QtUiFileHandler):
    def __init__(self, js_file_name):
        QtUiFileHandler.__init__(self, js_file_name)

    def startDocument(self):
        pass

    def startElement(self, name, attributes):
        if not self.tag_entry_handlers.has_key(name):
            if len(self.stack)> 0 and self.stack[-1].tag_entry_handlers.has_key(name):
                self.stack[-1].tag_entry_handlers[name](attributes, name)
            else:
                self.buffer.append("        // WARNING: %s entry is ignored" % name)

        else:
            self.tag_entry_handlers[name](attributes)

    def endElement(self, name):
        if not self.tag_exit_handlers.has_key(name):
            if len(self.stack) > 0 and self.stack[-1].tag_exit_handlers.has_key(name):
                self.stack[-1].tag_exit_handlers[name]()
            else:
                self.buffer.append("        // WARNING: %s exit is ignored" % name)
        else:
            self.tag_exit_handlers[name]()

    def characters(self, text):
        if text.isspace():
            return
        if len(self.stack) > 0:
            if self.stack[-1].xmltext_handler == None:
                if self.stack[-1].in_layout:
                    if self.stack[-1].layout.xmltext_handler != None:
                        print "\t\t",tuple(self.stack[-1].current),"is", text
                        self.stack[-1].layout.xmltext_handler(text, tuple(self.stack[-1].current))
                    else:
                        print "\t\t",tuple(self.stack[-1].current),"is", text, "(ignored)"
                        self.buffer.append("        // WARNING: %s: property text (%s) ignored" % (str(tuple(self.stack[-1].layout.current)), text))
                else:
                    if not isinstance(self.stack[-1], Dummy):
                        print "\t\t",tuple(self.stack[-1].current),"is", text, "(ignored)"
                        self.buffer.append("        // WARNING: %s: property text (%s) ignored" % (str(tuple(self.stack[-1].current)), text))
            else:
                print "\t\t",tuple(self.stack[-1].current),"is", text
                self.stack[-1].xmltext_handler(text, tuple(self.stack[-1].current))

    def endDocument(self):
        self.flush_buffers()

    def add_member(self, what):
        self.members.add(what)

    def flush_buffers(self):
        self.buffer = []
        self.buffers.append(self.buffer)
        if not isinstance(self.main_container, QMainWindow):
            self.buffer.append("        this.setWidget(%(self_parent)s);" % {'self_parent': self.main_container.name()})
        self.buffer.append("    }")
        self.buffer.append("    ,members : {")
        self.buffer.append(''.join(["        ", "\n        ,".join(self.members)]))
        self.buffer.append("    }")
        self.buffer.append("});")

        for b in self.buffers:
            self.js_file.write('\n'.join([bb.encode('utf8') for bb in b]))
            self.js_file.write('\n')

        self.js_file.close()
        del self.buffer[:]
        del self.buffers[:]

def qx_08(ui_file_name, js_file_name, root_namespace):
    global class_name

    f = open(js_file_name, 'w')
    class_name = js_file_name[js_file_name.rfind(root_namespace):].replace("//", "/").replace("/", ".")[0:-3]
    print js_file_name

    # Create a new parser instance, using the default XML engine SAX provides
    parser = sax.make_parser()

    # Create an instance of our handler class, which will be registered
    # to receive SAX events
    handler = QtUiFileParser(js_file_name)

    # Pass a file to be parsed, and pass the handler to be registered
    # to receive SAX events.
    sax.parse(ui_file_name, handler)

